unit PtPersist;

interface

uses
  Classes, SysUtils;

type
  IPtPersistRead = interface
    function PrevChar: char;
    function CurrChar: char;
    function ReadChar: char;
    function ReadString(const Terminator: char): string;
  end;

  IPtPersistWrite = interface
    procedure WriteChar(const ch: char);
    procedure WriteString(const Str: String);
    procedure WriteBytes(const Buf; const Size: integer);
  end;

  EPtPersist = class(Exception)
  end;

  // Stream implementations

  TPtPersistReadStream = class(TInterfacedObject, IPtPersistRead)
  private
    fStream : TStream;
    fPrev : char;
    fCurr : char;
  protected
    function PrevChar: Char;
    function CurrChar: Char;
    function ReadChar: Char;
    function ReadString(const Terminator: Char): String;
  public
    constructor Create(const Stream: TStream);
  end;

  TPtPersistWriteStream = class(TInterfacedObject, IPtPersistWrite)
  private
    fStream : TStream;
  protected
    procedure ThrowFailedToWrite;
    procedure WriteChar(const ch: Char);
    procedure WriteString(const Str: String);
    procedure WriteBytes(const Buf; const Size: Integer);
  public
    constructor Create(const Stream: TStream);
  end;

  // String implementations

  TPtPersistReadString = class(TInterfacedObject, IPtPersistRead)
  private
    fStr  : string;
    fLen  : integer;
    fNx   : integer;
  protected
    function PrevChar: Char;
    function CurrChar: Char;
    function ReadChar: Char;
    function ReadString(const Terminator: Char): String;
  public
    constructor Create(const Str: String);
  end;
{
  TPtPersistWriteString = class(TInterfacedObject, IPtPersistWrite)
  protected
    procedure WriteChar(const ch: Char);
    procedure WriteString(const Str: String);
    procedure WriteBytes(const Buf; const Size: Integer);
  public
    constructor Create;
  end;
}
implementation

{ TPtPersistReadStream }

constructor TPtPersistReadStream.Create(const Stream: TStream);
begin
  fStream := Stream;
end;

function TPtPersistReadStream.CurrChar: Char;
begin
  Result  := fCurr;
end;

function TPtPersistReadStream.PrevChar: Char;
begin
  Result  := fPrev;
end;

function TPtPersistReadStream.ReadChar: Char;
begin
  fPrev   := fCurr;
  if  fStream.Read(fCurr, 1) <> 1  then
    raise EPtPersist.Create('Input stream is exhausted');
  Result  := fCurr;
end;

function TPtPersistReadStream.ReadString(const Terminator: Char): String;
begin
  Result  := '';
  while ReadChar <> Terminator  do
    Result  := Result + fCurr;
end;

{ TPtPersistWriteStream }

constructor TPtPersistWriteStream.Create(const Stream: TStream);
begin
  fStream := Stream;
end;

procedure TPtPersistWriteStream.ThrowFailedToWrite;
begin
  raise EPtPersist.Create('Failed to write to output stream');
end;

procedure TPtPersistWriteStream.WriteBytes(const Buf; const Size: Integer);
begin
  if  fStream.Write(Buf, Size) <> Size then
    ThrowFailedToWrite;
end;

procedure TPtPersistWriteStream.WriteChar(const ch: Char);
begin
  if  fStream.Write(ch, 1) <> 1 then
    ThrowFailedToWrite;
end;

procedure TPtPersistWriteStream.WriteString(const Str: String);
var
  len : integer;
begin
  len := Length(Str);
  if  fStream.Write(str[1], len) <> len then
    ThrowFailedToWrite;
end;

{ TPtPersistReadString }

constructor TPtPersistReadString.Create(const Str: String);
begin
  fStr  := Str;
  fLen  := Length(fStr);
  fNx   := 0;
end;

function TPtPersistReadString.CurrChar: Char;
begin
  Result  := fStr[fNx];
end;

function TPtPersistReadString.PrevChar: Char;
begin

end;

function TPtPersistReadString.ReadChar: Char;
begin
  if  fNx >= fLen then
    raise EPtPersist.Create('Input string is exhausted');
  inc(fNx);
  Result  := fStr[fNx];
end;

function TPtPersistReadString.ReadString(const Terminator: Char): String;
begin
  Result  := '';
  while ReadChar <> Terminator  do
    Result  := Result + CurrChar;
end;

end.
